/**
 * 金额转中文
 * 思路：                       
 *                             个
 *      十     百      千       万
 *      十万   百万    千万      亿 
 *      十亿   百亿    千亿      万亿
 *                              
 *                              0
 *      1      2       3        4
 *      5      6       7        8   
 *      9      10      11       12
 * 
 * 计算步骤
 * 1. 获取当前数值大小
 * 2. 排除个位后 数值按个，十，百，千有规律的重复 所以计算其和4的余数 pos % 4
 * 3. 补充最大单位，例如上面第三，四行的万和亿
 *    pos = 0 ~ 3 没有最大单位
 *    pos = 4 ~ 7 最大单位是万
 *    pos = 8 ~ 11 最大单位是亿
 *    pos / 4 的整数就是最大单位
 */
 export function getAmountChinese ( val ) {
    const amount = +val
    if ( Number.isNaN( amount ) || amount < 0 ) return ''
    const NUMBER = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
    const N_UNIT1 = ['', '拾', '佰', '仟']
    const N_UNIT2 = ['', '万', '亿', '万亿']
    const D_UNIT = ['角', '分', '厘', '毫']
    let [integer, decimal] = amount.toString().split( '.' )
    if ( integer && integer.length > 12 ) return '金额过大无法计算'
    let res = ''
    // 整数部分
    if ( integer ) {
      for ( let i = 0, len = integer.length; i < len; i++ ) {
        const num = integer.charAt( i );
        const isZero = num === '0';
        const pos = len - i - 1; // 排除个位后 所处的索引位置
        const isMaxUniPos = pos % 4 === 0;
        const isZeroNext = integer.charAt( i + 1 ) === '0';
        if ( !(isZero && (isZeroNext || isMaxUniPos))) { // 当前位 等于 0 且下一位也等于 0 则可跳过计算
          res += NUMBER[num];
          if (!isZero) res += N_UNIT1[pos % 4];
        }
        if(isMaxUniPos) {
          res += N_UNIT2[Math.floor( pos / 4 )];
        }
      }
      res += '圆'
    }
    // 小数部分
    if ( parseInt( decimal ) ) {
      const loopCount = Math.min(decimal.length, 4);
      for ( let i = 0; i < loopCount; i++ ) {
        const num = decimal.charAt( i )
        if ( num !== '0' ) res += NUMBER[num] + D_UNIT[i];
      }
    } else {
      res += '整'
    }
    return res
  }
  
  /**
   * 计算两个时间差经历的时间的文字描述
   * @param {*} timestamp - 毫秒
   */
  export const timeCalculate = ( start, end ) => {
    const label = ['分钟', '小时', '天', '月', '年']
    const unit = [60, 60, 24, 30, 12]
    let restTime = Math.floor( ( end - start ) / 1000 )
    let res = ''
    for ( let i = 0, len = unit.length; i < len; i++ ) {
      const pos = len - i // 从年开始算，分钟换算成年 === Math.pow(60, 4)
      const temp = unit.slice( 0, pos ).reduce( ( p, c ) => p * c, 1 )
      const time = Math.floor( restTime / temp )
      time > 0 && ( res += time + label[pos - 1] )
      restTime -= time * temp
    }
    return res
  }
  
  
  /**
   * 简易防抖函数
   * @param {Function} func -防抖目标函数
   * @param {Number}} gap - 防抖时间间隔
   */
  export const debounce = ( func, gap ) => {
    let timer
    return function () {
      timer && clearTimeout( timer )
      timer = setTimeout( () => {
        func.apply( this, arguments )
      }, gap )
    }
  }
  /**
   * 下划线转驼峰
   * @param {String} name - 字符串
   */
  export const toHump = name => name.replace( /\_(\w)/g, function ( all, letter ) {
    return letter.toUpperCase()
  } )
  /**
   * 将用户输入的连续单个数字合并为一个数
   * @param {Array} expressions - 记录计算表达式的数组
   * @returns {Array} 新的数组
   */
  export const mergeNumberOfExps = expressions => {
    const res = []
    const isNumChar = n => /^[\d|\.]$/.test( n )
    for ( let i = 0; i < expressions.length; i++ ) {
      if ( i > 0 && isNumChar( expressions[i - 1] ) && isNumChar( expressions[i] ) ) {
        res[res.length - 1] += expressions[i]
        continue
      }
      res.push( expressions[i] )
    }
    return res
  }
  /**
   * 校验表达式是否符合计算法则
   * @param {Array} expressions - 合并数字后的表达式数组
   * @returns {Boolean}
   */
  export const validExp = ( expressions, mergeNum = true ) => {
    const temp = mergeNum ? mergeNumberOfExps( expressions ) : expressions
    const arr = temp.filter( t => !'()'.includes( t ) )
    // 去括号后 length应该为奇数  并且第一个字符和最后一个字符应该为数字而非计算符号
    if ( temp.length % 2 === 0 || arr.length % 2 === 0 || Number.isNaN( +arr[0] ) || Number.isNaN( +arr[arr.length - 1] ) ) {
      return false
    }
    for ( let i = 0; i < arr.length - 1; i += 2 ) {
      if ( typeof ( +arr[i] ) !== 'number' || !Number.isNaN( +arr[i + 1] ) ) return false
    }
    return true
  }
  
  /**
   * 中缀转后缀（逆波兰 Reverse Polish Notation）
   * @param {Array} exps - 中缀表达式数组
   */
  export const toRPN = exps => {
    const s1 = [] // 符号栈
    const s2 = [] // 输出栈
    const getTopVal = ( stack ) => stack.length > 0 ? stack[stack.length - 1] : null
    const levelCompare = ( c1, c2 ) => {
      const getIndex = c => ['+-', '×÷', '()'].findIndex( t => t.includes( c ) )
      return getIndex( c1 ) - getIndex( c2 )
    }
    exps.forEach( t => {
      if ( typeof t === 'string' && Number.isNaN( Number( t ) ) ) { // 是符号
        if ( t === '(' ) {
          s1.push( t )
        } else if ( t === ')' ) {
          let popVal
          do {
            popVal = s1.pop()
            popVal !== '(' && s2.push( popVal )
          } while ( s1.length && popVal !== '(' )
        } else {
          let topVal = getTopVal( s1 )
          if ( !topVal ) { // s1 为空 直接push
            s1.push( t )
          } else {
            while ( topVal && topVal !== '(' && levelCompare( topVal, t ) >= 0 ) { // 优先级 >= t 弹出到s2
              s2.push( s1.pop() )
              topVal = getTopVal( s1 )
            }
            s1.push( t )
          }
        }
        return
      }
      s2.push( t ) // 数字直接入栈
    } )
    while ( s1.length ) {
      s2.push( s1.pop() )
    }
    return s2
  }
  /**
   * 计算后缀表达式的值
   * @param {Array} rpnExps - 后缀表达式
   */
  export const calcRPN = rpnExps => {
    rpnExps = rpnExps.concat()
    const calc = ( x, y, type ) => {
      let a1 = Number( x ), a2 = Number( y )
      switch ( type ) {
        case '+': return a1 + a2;
        case '-': return a1 - a2;
        case '×': return a1 * a2;
        case '÷': return a1 / a2;
      }
    }
    for ( let i = 2; i < rpnExps.length; i++ ) {
      if ( '+-×÷'.includes( rpnExps[i] ) ) {
        let val = calc( rpnExps[i - 2], rpnExps[i - 1], rpnExps[i] )
        rpnExps.splice( i - 2, 3, val )
        i = i - 2
      }
    }
    return rpnExps[0]
  }

  export default {}